package controllers

import (
	"context"
	"time"

	"github.com/go-logr/logr"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"

	daqv1 "node-operator/api/v1"
	"node-operator/report"

	corev1 "k8s.io/api/core/v1"
)

// NodeReconciler reconciles a Node object
type NodeReconciler struct {
	client.Client
	Logger logr.Logger
}

var (
	nodeStoppedMessage string = "Kubelet stopped posting node status."
)

//+kubebuilder:rbac:groups=core,resources=nodes,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=core,resources=nodes/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=core,resources=nodes/finalizers,verbs=update

// https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.8.3/pkg/reconcile
func (r *NodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	// #############your logic here##############
	var node corev1.Node
	client := r.Client
	if err := client.Get(ctx, req.NamespacedName, &node); err != nil {
		r.Logger.Error(err, "Can't get node")
	} else {
		r.Logger.Info("Get node update", "node name", node.GetName())
		if r.nodeStopped(&node) {
			r.deleteNode(ctx, &node)
			// 给reporter发送被删除的node
			delNode := daqv1.Node{
				Name:  node.Name,
				IP:    node.Status.Addresses[0].Address,
				InK8s: "False",
				Status: daqv1.NodeStatus{
					Ready: "False",
					Time:  time.Now().UnixNano() / 1e6,
				},
			}
			report.DeletedNodeReportChan <- &delNode
		} else {
			// 给reporter发送更新的node
			upNode := daqv1.Node{
				Name:  node.Name,
				IP:    node.Status.Addresses[0].Address,
				InK8s: "True",
				Status: daqv1.NodeStatus{
					Ready: "True",
					Time:  time.Now().UnixNano() / 1e6,
				},
			}
			report.UpdateNodeReportChan <- &upNode
		}
	}

	return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *NodeReconciler) SetupWithManager(mgr ctrl.Manager) error {
	return ctrl.NewControllerManagedBy(mgr).
		For(&corev1.Node{}).
		Complete(r)
}

func (r *NodeReconciler) deleteNode(ctx context.Context, node *corev1.Node) {
	r.Logger.Info("Delete stopped node ", "node name", node.Name)
	cli := r.Client
	if err := cli.Delete(ctx, node); err != nil {
		r.Logger.Info("Delete stopped node failed", "node name", node.Name)
	}
}

func (r *NodeReconciler) nodeReady(node *corev1.Node) bool {
	condition := node.Status.Conditions[len(node.Status.Conditions)-1]
	ready := false
	if condition.Type == corev1.NodeReady && condition.Status == corev1.ConditionTrue {
		ready = true
	}

	return ready
}

func (r *NodeReconciler) nodeStopped(node *corev1.Node) bool {
	condition := node.Status.Conditions[len(node.Status.Conditions)-1]
	stopped := false
	if condition.Message == nodeStoppedMessage {
		//node 停止了
		stopped = true
	}
	return stopped
}
